import pyaudio
import numpy as np
import logging
from voice_assistant.my_state import app_state
from voice_assistant.com_utils import calculate_rms, min_max_scaled, run_in_thread

logger = logging.getLogger("VoiceAssistant")

# 配置
SAMPLE_RATE = 16000
CHUNK_SIZE = 480
FORMAT = pyaudio.paInt16
CHANNELS = 1
SILENCE_THRESHOLD = 300
SILENCE_TIMEOUT = 10.0
MAX_SILENCE_FRAMES = int(SILENCE_TIMEOUT * 1000 / (CHUNK_SIZE * 1000 / SAMPLE_RATE))

class VoiceRecorder:
    def __init__(self):
        self.is_running = True
        self.audio = None
        self.stream = None
        app_state.recorder = self
        
        try:
            self.audio = pyaudio.PyAudio()
        except Exception as e:
            logger.error(f"无法初始化PyAudio: {str(e)}")
            return

    def start(self):
        """启动录音线程"""
        run_in_thread(self.record)
        logger.info("录音线程已启动")
    
    def record(self):
        """录音线程主函数"""
        if self.setup_microphone() is None:
            return
            
        # 重置计数器
        app_state.silence_counter = 0 
        audio_buffer = [] # 语音段缓冲区
        consecutive_silence = 0 # 连续静音帧计数
        MAX_CONSECUTIVE_SILENCE = 30 # 连续帧低电平视为语音结束
        has_audio = False # 标记缓冲区中是否有有效语音
        
        logger.info("开始持续处理音频...")
        
        while self.is_running:
            try:
                data = self.stream.read(CHUNK_SIZE, exception_on_overflow=False)
                audio_data = np.frombuffer(data, dtype=np.int16)
                
                # 计算并更新波形
                rms = calculate_rms(audio_data)
                waveform = min_max_scaled(int(rms / 30), 1, 100)
                app_state.wave_bars.append(waveform)
                if len(app_state.wave_bars) > 30:
                    app_state.wave_bars.pop(0)
                
                # 静音检测
                audio_buffer.append(data)
                speaking = rms > SILENCE_THRESHOLD
                
                if speaking:
                    consecutive_silence = 0
                    has_audio = True
                    app_state.silence_counter = 0
                else:
                    consecutive_silence += 1
                    app_state.silence_counter += 1
                    
                    # 如果达到连续静音帧且缓冲区有数据
                    if consecutive_silence >= MAX_CONSECUTIVE_SILENCE and audio_buffer:
                        if has_audio:
                            app_state.audio_queue.put(b''.join(audio_buffer))
                        audio_buffer = []
                        consecutive_silence = 0
                        has_audio = False
                    
                    # 10秒静音超时自动转为待唤醒状态
                    if app_state.silence_counter > MAX_SILENCE_FRAMES and app_state.wake_word_detected:
                        logger.info("检测到长时间静音，转为待唤醒状态")
                        app_state.is_recording = False
                        app_state.wake_word_detected = False
                        app_state.waiting_for_wake = True
                        app_state.silence_counter = 0
            except Exception as e:
                logger.error(f"音频处理错误: {str(e)}")
    
    def setup_microphone(self):
        """设置麦克风输入"""
        if not self.audio:
            return None
            
        try:
            device_index = self.find_input_device()
            if device_index is None:
                logger.error("错误: 未找到音频设备!")
                return None
        
            self.stream = self.audio.open(
                format=FORMAT,
                channels=CHANNELS,
                rate=SAMPLE_RATE,
                input=True,
                input_device_index=device_index,
                frames_per_buffer=CHUNK_SIZE
            )
            logger.info("麦克风输入已启用")
            return self.stream
        except Exception as e:
            logger.error(f"无法打开麦克风: {str(e)}")
            return None
            
    def find_input_device(self):
        """寻找最佳输入设备"""
        for i in range(self.audio.get_device_count()):
            dev_info = self.audio.get_device_info_by_index(i)
            if dev_info["maxInputChannels"] > 0:
                return i
        return None
    
    def stop(self):
        """停止录音和清理资源"""
        self.is_running = False
        if self.stream:
            self.stream.stop_stream()
            self.stream.close()
        if self.audio:
            self.audio.terminate()
        logger.info("录音器已停止")